home *** CD-ROM | disk | FTP | other *** search
/ Clickx 115 / Clickx 115.iso / software / tools / windows / tails-i386-0.16.iso / live / filesystem.squashfs / sbin / fsadm < prev    next >
Encoding:
Text File  |  2011-01-23  |  11.1 KB  |  407 lines

  1. #!/bin/bash
  2. #
  3. # Copyright (C) 2007-2009 Red Hat, Inc. All rights reserved.
  4. #
  5. # This file is part of LVM2.
  6. #
  7. # This copyrighted material is made available to anyone wishing to use,
  8. # modify, copy, or redistribute it subject to the terms and conditions
  9. # of the GNU General Public License v.2.
  10. #
  11. # You should have received a copy of the GNU General Public License
  12. # along with this program; if not, write to the Free Software Foundation,
  13. # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  14. #
  15. # Author: Zdenek Kabelac <zkabelac at redhat.com>
  16. #
  17. # Script for resizing devices (usable for LVM resize)
  18. #
  19. # Needed utilities:
  20. #   mount, umount, grep, readlink, blockdev, blkid, fsck, xfs_check
  21. #
  22. # ext2/ext3/ext4: resize2fs, tune2fs
  23. # reiserfs: resize_reiserfs, reiserfstune
  24. # xfs: xfs_growfs, xfs_info
  25. #
  26.  
  27. TOOL=fsadm
  28.  
  29. PATH=/sbin:/usr/sbin:/bin:/usr/sbin:$PATH
  30.  
  31. # utilities
  32. TUNE_EXT=tune2fs
  33. RESIZE_EXT=resize2fs
  34. TUNE_REISER=reiserfstune
  35. RESIZE_REISER=resize_reiserfs
  36. TUNE_XFS=xfs_info
  37. RESIZE_XFS=xfs_growfs
  38.  
  39. MOUNT=mount
  40. UMOUNT=umount
  41. MKDIR=mkdir
  42. RMDIR=rmdir
  43. BLOCKDEV=blockdev
  44. BLKID=blkid
  45. GREP=grep
  46. READLINK=readlink
  47. READLINK_E="-e"
  48. FSCK=fsck
  49. XFS_CHECK=xfs_check
  50.  
  51. # user may override lvm location by setting LVM_BINARY
  52. LVM=${LVM_BINARY-lvm}
  53.  
  54. YES=
  55. DRY=0
  56. VERB=
  57. FORCE=
  58. EXTOFF=0
  59. DO_LVRESIZE=0
  60. FSTYPE=unknown
  61. VOLUME=unknown
  62. TEMPDIR="${TMPDIR:-/tmp}/${TOOL}_${RANDOM}$$/m"
  63. BLOCKSIZE=
  64. BLOCKCOUNT=
  65. MOUNTPOINT=
  66. MOUNTED=
  67. REMOUNT=
  68.  
  69. IFS_OLD=$IFS
  70. # without bash $'\n'
  71. NL='
  72. '
  73.  
  74. tool_usage() {
  75.     echo "${TOOL}: Utility to resize or check the filesystem on a device"
  76.     echo
  77.     echo "  ${TOOL} [options] check device"
  78.     echo "    - Check the filesystem on device using fsck"
  79.     echo
  80.     echo "  ${TOOL} [options] resize device [new_size[BKMGTPE]]"
  81.     echo "    - Change the size of the filesystem on device to new_size"
  82.     echo
  83.     echo "  Options:"
  84.     echo "    -h | --help         Show this help message"
  85.     echo "    -v | --verbose      Be verbose"
  86.     echo "    -e | --ext-offline  unmount filesystem before ext2/ext3/ext4 resize"
  87.     echo "    -f | --force        Bypass sanity checks"
  88.     echo "    -n | --dry-run      Print commands without running them"
  89.     echo "    -l | --lvresize     Resize given device (if it is LVM device)"
  90.     echo "    -y | --yes          Answer \"yes\" at any prompts"
  91.     echo
  92.     echo "  new_size - Absolute number of filesystem blocks to be in the filesystem,"
  93.     echo "             or an absolute size using a suffix (in powers of 1024)."
  94.     echo "             If new_size is not supplied, the whole device is used."
  95.  
  96.     exit
  97. }
  98.  
  99. verbose() {
  100.     test -n "$VERB" && echo "$TOOL: $@" || true
  101. }
  102.  
  103. error() {
  104.     echo "$TOOL: $@" >&2
  105.     cleanup 1
  106. }
  107.  
  108. dry() {
  109.     if [ "$DRY" -ne 0 ]; then
  110.         verbose "Dry execution $@"
  111.         return 0
  112.     fi
  113.     verbose "Executing $@"
  114.     $@
  115. }
  116.  
  117. cleanup() {
  118.     trap '' 2
  119.     # reset MOUNTPOINT - avoid recursion
  120.     test "$MOUNTPOINT" = "$TEMPDIR" && MOUNTPOINT="" temp_umount
  121.     if [ -n "$REMOUNT" ]; then
  122.         verbose "Remounting unmounted filesystem back"
  123.         dry $MOUNT "$VOLUME" "$MOUNTED"
  124.     fi
  125.     IFS=$IFS_OLD
  126.     trap 2
  127.  
  128.     # start LVRESIZE with the filesystem modification flag
  129.     # and allow recursive call of fsadm
  130.     unset FSADM_RUNNING
  131.     test "$DO_LVRESIZE" -eq 2 && exec $LVM lvresize $VERB -r -L$(( $NEWSIZE / 1048576 )) $VOLUME
  132.     exit ${1:-0}
  133. }
  134.  
  135. # convert parameter from Exa/Peta/Tera/Giga/Mega/Kilo/Bytes and blocks
  136. # (2^(60/50/40/30/20/10/0))
  137. decode_size() {
  138.     case "$1" in
  139.      *[eE]) NEWSIZE=$(( ${1%[eE]} * 1152921504606846976 )) ;;
  140.      *[pP]) NEWSIZE=$(( ${1%[pP]} * 1125899906842624 )) ;;
  141.      *[tT]) NEWSIZE=$(( ${1%[tT]} * 1099511627776 )) ;;
  142.      *[gG]) NEWSIZE=$(( ${1%[gG]} * 1073741824 )) ;;
  143.      *[mM]) NEWSIZE=$(( ${1%[mM]} * 1048576 )) ;;
  144.      *[kK]) NEWSIZE=$(( ${1%[kK]} * 1024 )) ;;
  145.      *[bB]) NEWSIZE=${1%[bB]} ;;
  146.          *) NEWSIZE=$(( $1 * $2 )) ;;
  147.     esac
  148.     #NEWBLOCKCOUNT=$(round_block_size $NEWSIZE $2)
  149.     NEWBLOCKCOUNT=$(( $NEWSIZE / $2 ))
  150.  
  151.     if [ $DO_LVRESIZE -eq 1 ]; then
  152.         # start lvresize, but first cleanup mounted dirs
  153.         DO_LVRESIZE=2
  154.         cleanup 0
  155.     fi
  156. }
  157.  
  158. # detect filesystem on the given device
  159. # dereference device name if it is symbolic link
  160. detect_fs() {
  161.         VOLUME=${1#/dev/}
  162.     VOLUME=$($READLINK $READLINK_E "/dev/$VOLUME") || error "Cannot get readlink $1"
  163.     # strip newline from volume name
  164.     VOLUME=${VOLUME%%$NL}
  165.     # use /dev/null as cache file to be sure about the result
  166.     # not using option '-o value' to be compatible with older version of blkid
  167.     FSTYPE=$($BLKID -c /dev/null -s TYPE "$VOLUME") || error "Cannot get FSTYPE of \"$VOLUME\""
  168.     FSTYPE=${FSTYPE##*TYPE=\"} # cut quotation marks
  169.     FSTYPE=${FSTYPE%%\"*}
  170.     verbose "\"$FSTYPE\" filesystem found on \"$VOLUME\""
  171. }
  172.  
  173. # check if the given device is already mounted and where
  174. detect_mounted()  {
  175.     $MOUNT >/dev/null || error "Cannot detect mounted device $VOLUME"
  176.     MOUNTED=$($MOUNT | $GREP "$VOLUME")
  177.     MOUNTED=${MOUNTED##* on }
  178.     MOUNTED=${MOUNTED% type *} # allow type in the mount name
  179.     test -n "$MOUNTED"
  180. }
  181.  
  182. # get the full size of device in bytes
  183. detect_device_size() {
  184.     # check if blockdev supports getsize64
  185.     $BLOCKDEV 2>&1 | $GREP getsize64 >/dev/null
  186.     if test $? -eq 0; then
  187.         DEVSIZE=$($BLOCKDEV --getsize64 "$VOLUME") || error "Cannot read size of device \"$VOLUME\""
  188.     else
  189.         DEVSIZE=$($BLOCKDEV --getsize "$VOLUME") || error "Cannot read size of device \"$VOLUME\""
  190.         SSSIZE=$($BLOCKDEV --getss "$VOLUME") || error "Cannot block size read device \"$VOLUME\""
  191.         DEVSIZE=$(($DEVSIZE * $SSSIZE))
  192.     fi
  193. }
  194.  
  195. # round up $1 / $2
  196. # could be needed to gaurantee 'at least given size'
  197. # but it makes many troubles
  198. round_up_block_size() {
  199.     echo $(( ($1 + $2 - 1) / $2 ))
  200. }
  201.  
  202. temp_mount() {
  203.     dry $MKDIR -p -m 0000 "$TEMPDIR" || error "Failed to create $TEMPDIR"
  204.     dry $MOUNT "$VOLUME" "$TEMPDIR" || error "Failed to mount $TEMPDIR"
  205. }
  206.  
  207. temp_umount() {
  208.     dry $UMOUNT "$TEMPDIR" || error "Failed to umount $TEMPDIR"
  209.     dry $RMDIR "${TEMPDIR}" || error "Failed to remove $TEMPDIR"
  210.     dry $RMDIR "${TEMPDIR%%m}" || error "Failed to remove ${TEMPDIR%%m}"
  211. }
  212.  
  213. yes_no() {
  214.     echo -n "$@? [Y|n] "
  215.  
  216.     if [ -n "$YES" ]; then
  217.         echo y ; return 0
  218.     fi
  219.  
  220.     while read -r -s -n 1 ANS ; do
  221.         case "$ANS" in
  222.          "y" | "Y" | "") echo y ; return 0 ;;
  223.          "n" | "N") echo n ; return 1 ;;
  224.         esac
  225.     done
  226. }
  227.  
  228. try_umount() {
  229.     yes_no "Do you want to unmount \"$MOUNTED\"" && dry $UMOUNT "$MOUNTED" && return 0
  230.     error "Can not proceed with mounted filesystem \"$MOUNTED\""
  231. }
  232.  
  233. validate_parsing() {
  234.     test -n "$BLOCKSIZE" -a -n "$BLOCKCOUNT" || error "Cannot parse $1 output"
  235. }
  236. ####################################
  237. # Resize ext2/ext3/ext4 filesystem
  238. # - unmounted or mounted for upsize
  239. # - unmounted for downsize
  240. ####################################
  241. resize_ext() {
  242.     verbose "Parsing $TUNE_EXT -l \"$VOLUME\""
  243.     for i in $($TUNE_EXT -l "$VOLUME"); do
  244.         case "$i" in
  245.           "Block size"*) BLOCKSIZE=${i##*  } ;;
  246.           "Block count"*) BLOCKCOUNT=${i##*  } ;;
  247.         esac
  248.     done
  249.     validate_parsing $TUNE_EXT
  250.     decode_size $1 $BLOCKSIZE
  251.     FSFORCE=$FORCE
  252.  
  253.     if [ "$NEWBLOCKCOUNT" -lt "$BLOCKCOUNT" -o "$EXTOFF" -eq 1 ]; then
  254.         detect_mounted && verbose "$RESIZE_EXT needs unmounted filesystem" && try_umount
  255.         REMOUNT=$MOUNTED
  256.         # CHECKME: after umount resize2fs requires fsck or -f flag.
  257.         FSFORCE="-f"
  258.     fi
  259.  
  260.     verbose "Resizing filesystem on device \"$VOLUME\" to $NEWSIZE bytes ($BLOCKCOUNT -> $NEWBLOCKCOUNT blocks of $BLOCKSIZE bytes)"
  261.     dry $RESIZE_EXT $FSFORCE "$VOLUME" $NEWBLOCKCOUNT
  262. }
  263.  
  264. #############################
  265. # Resize reiserfs filesystem
  266. # - unmounted for upsize
  267. # - unmounted for downsize
  268. #############################
  269. resize_reiser() {
  270.     detect_mounted && verbose "ReiserFS resizes only unmounted filesystem" && try_umount
  271.     REMOUNT=$MOUNTED
  272.     verbose "Parsing $TUNE_REISER \"$VOLUME\""
  273.     for i in $($TUNE_REISER "$VOLUME"); do
  274.         case "$i" in
  275.           "Blocksize"*) BLOCKSIZE=${i##*: } ;;
  276.           "Count of blocks"*) BLOCKCOUNT=${i##*: } ;;
  277.         esac
  278.     done
  279.     validate_parsing $TUNE_REISER
  280.     decode_size $1 $BLOCKSIZE
  281.     verbose "Resizing \"$VOLUME\" $BLOCKCOUNT -> $NEWBLOCKCOUNT blocks ($NEWSIZE bytes, bs: $NEWBLOCKCOUNT)"
  282.     if [ -n "$YES" ]; then
  283.         dry echo y | $RESIZE_REISER -s $NEWSIZE "$VOLUME"
  284.     else
  285.         dry $RESIZE_REISER -s $NEWSIZE "$VOLUME"
  286.     fi
  287. }
  288.  
  289. ########################
  290. # Resize XFS filesystem
  291. # - mounted for upsize
  292. # - can not downsize
  293. ########################
  294. resize_xfs() {
  295.     detect_mounted
  296.     MOUNTPOINT=$MOUNTED
  297.     if [ -z "$MOUNTED" ]; then
  298.         MOUNTPOINT=$TEMPDIR
  299.         temp_mount || error "Cannot mount Xfs filesystem"
  300.     fi
  301.     verbose "Parsing $TUNE_XFS \"$MOUNTPOINT\""
  302.     for i in $($TUNE_XFS "$MOUNTPOINT"); do
  303.         case "$i" in
  304.           "data"*) BLOCKSIZE=${i##*bsize=} ; BLOCKCOUNT=${i##*blocks=} ;;
  305.         esac
  306.     done
  307.     BLOCKSIZE=${BLOCKSIZE%%[^0-9]*}
  308.     BLOCKCOUNT=${BLOCKCOUNT%%[^0-9]*}
  309.     validate_parsing $TUNE_XFS
  310.     decode_size $1 $BLOCKSIZE
  311.     if [ $NEWBLOCKCOUNT -gt $BLOCKCOUNT ]; then
  312.         verbose "Resizing Xfs mounted on \"$MOUNTPOINT\" to fill device \"$VOLUME\""
  313.         dry $RESIZE_XFS $MOUNTPOINT
  314.     elif [ $NEWBLOCKCOUNT -eq $BLOCKCOUNT ]; then
  315.         verbose "Xfs filesystem already has the right size"
  316.     else
  317.         error "Xfs filesystem shrinking is unsupported"
  318.     fi
  319. }
  320.  
  321. ####################
  322. # Resize filesystem
  323. ####################
  324. resize() {
  325.     NEWSIZE=$2
  326.     detect_fs "$1"
  327.     detect_device_size
  328.     verbose "Device \"$VOLUME\" size is $DEVSIZE bytes"
  329.     # if the size parameter is missing use device size
  330.     #if [ -n "$NEWSIZE" -a $NEWSIZE <
  331.     test -z "$NEWSIZE" && NEWSIZE=${DEVSIZE}b
  332.     trap cleanup 2
  333.     IFS=$NL
  334.     case "$FSTYPE" in
  335.       "ext3"|"ext2"|"ext4") resize_ext $NEWSIZE ;;
  336.       "reiserfs") resize_reiser $NEWSIZE ;;
  337.       "xfs") resize_xfs $NEWSIZE ;;
  338.       *) error "Filesystem \"$FSTYPE\" on device \"$VOLUME\" is not supported by this tool" ;;
  339.     esac || error "Resize $FSTYPE failed"
  340.     cleanup 0
  341. }
  342.  
  343. ###################
  344. # Check filesystem
  345. ###################
  346. check() {
  347.     detect_fs "$1"
  348.     detect_mounted && error "Can not fsck device \"$VOLUME\", filesystem mounted on $MOUNTED"
  349.     case "$FSTYPE" in
  350.       "xfs") dry $XFS_CHECK "$VOLUME" ;;
  351.       *) dry $FSCK $YES "$VOLUME" ;;
  352.     esac
  353. }
  354.  
  355. #############################
  356. # start point of this script
  357. # - parsing parameters
  358. #############################
  359.  
  360. # test if we are not invoked recursively
  361. test -n "$FSADM_RUNNING" && exit 0
  362.  
  363. # test some prerequisities
  364. test -n "$TUNE_EXT" -a -n "$RESIZE_EXT" -a -n "$TUNE_REISER" -a -n "$RESIZE_REISER" \
  365.   -a -n "$TUNE_XFS" -a -n "$RESIZE_XFS" -a -n "$MOUNT" -a -n "$UMOUNT" -a -n "$MKDIR" \
  366.   -a -n "$RMDIR" -a -n "$BLOCKDEV" -a -n "$BLKID" -a -n "$GREP" -a -n "$READLINK" \
  367.   -a -n "$FSCK" -a -n "$XFS_CHECK" -a -n "LVM" \
  368.   || error "Required command definitions in the script are missing!"
  369.  
  370. $LVM version >/dev/null 2>&1 || error "Could not run lvm binary '$LVM'"
  371. $($READLINK -e / >/dev/null 2>&1) || READLINK_E="-f"
  372. TEST64BIT=$(( 1000 * 1000000000000 ))
  373. test $TEST64BIT -eq 1000000000000000 || error "Shell does not handle 64bit arithmetic"
  374. $(echo Y | $GREP Y >/dev/null) || error "Grep does not work properly"
  375.  
  376.  
  377. if [ "$#" -eq 0 ] ; then
  378.     tool_usage
  379. fi
  380.  
  381. while [ "$#" -ne 0 ]
  382. do
  383.      case "$1" in
  384.       "") ;;
  385.       "-h"|"--help") tool_usage ;;
  386.       "-v"|"--verbose") VERB="-v" ;;
  387.       "-n"|"--dry-run") DRY=1 ;;
  388.       "-f"|"--force") FORCE="-f" ;;
  389.       "-e"|"--ext-offline") EXTOFF=1 ;;
  390.       "-y"|"--yes") YES="-y" ;;
  391.       "-l"|"--lvresize") DO_LVRESIZE=1 ;;
  392.       "check") CHECK="$2" ; shift ;;
  393.       "resize") RESIZE="$2"; NEWSIZE="$3" ; shift 2 ;;
  394.       *) error "Wrong argument \"$1\". (see: $TOOL --help)"
  395.     esac
  396.     shift
  397. done
  398.  
  399. if [ -n "$CHECK" ]; then
  400.     check "$CHECK"
  401. elif [ -n "$RESIZE" ]; then
  402.     export FSADM_RUNNING="fsadm"
  403.     resize "$RESIZE" "$NEWSIZE"
  404. else
  405.     error "Missing command. (see: $TOOL --help)"
  406. fi
  407.